/**
 * 
 */
package com.myworld.distributedLock;

import java.util.UUID;

import org.apache.commons.lang3.StringUtils;
/**
 * 分布式锁对象<br>
 * 用户辅助加锁操作 
 */
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class DistributedLock {
        private final static Logger logger=LoggerFactory.getLogger(DistributedLock.class);
         /**
     * 默认的锁的超时时长，单位ms,默认60秒
     */
    public static final int DEFAULT_EXPIRY_TIME_MILLIS = Integer.getInteger("com.hori.jedis.lock.expiry.millis", 60 * 1000);
        private static DistributedLock NO_LOCK=new DistributedLock("default",new UUID(0l,0l), 0l);
        /**
         * 锁的key
         */
        private String lockKey;
    /**
     * uuid，用于更精确辅助判断锁对象信息的比较是否一致
     */
        private UUID uuid;
        /**
         * 锁的超时时间点的时间戳毫秒，注意是时间戳
         */
    private long expiryTime;
    /**
     * 获取锁是否成功的标志，用于控制释放锁的误操作，只有lockSuccess为true时，才能释放锁
     */
    private boolean lockSuccess=false;
    /**
     * 无参构造函数是私有的
     */
    private DistributedLock(){
        
    }
    /**
     * 构造函数<br>
     * 默认锁的超时时间60s
     * @param lockKey 锁的名称，注意保持其可识别性；lockKey不能包含冒号:分隔
     */
    public DistributedLock(String lockKey) {
        if(StringUtils.isBlank(lockKey)){
            throw new RuntimeException("DistributedLock lockKey cannot be null");
        }
        if(-1!=lockKey.indexOf(":")){//lockKey不能使用冒号:分隔
            throw new RuntimeException("DistributedLock lockKey不能包含冒号:分隔");
        }
        this.lockKey=lockKey;
        this.uuid = UUID.randomUUID();
        long expiryTimeMillis=DEFAULT_EXPIRY_TIME_MILLIS;
        this.expiryTime = System.currentTimeMillis()+expiryTimeMillis;//###加上当前系统时间，转成时间戳
        this.lockSuccess=false;
    }
    /**
     * 构造函数,外部调用
     * @param lockKey 锁的名称，注意保持其可识别性；lockKey不能包含冒号:分隔
     * @param expiryTimeMillis 锁的超时时间，单位ms,如锁超时时间60秒，则是60*1000
     */
    public DistributedLock(String lockKey, long expiryTimeMillis) {
        if(StringUtils.isBlank(lockKey)){
            throw new RuntimeException("DistributedLock lockKey cannot be null");
        }
        if(-1!=lockKey.indexOf(":")){//lockKey不能使用冒号:分隔
            throw new RuntimeException("DistributedLock lockKey不能包含冒号:分隔");
        }
        this.lockKey=lockKey;
        this.uuid = UUID.randomUUID();
        this.expiryTime = System.currentTimeMillis()+expiryTimeMillis;//###加上当前系统时间，转成时间戳
        this.lockSuccess=false;
    }
    /**
     * 构造函数，私有构造函数
     * @param lockKey 锁的名称，注意保存可识别性，同时用于控制锁的粒度
     * @param expiryTimeMillis 锁的超时时间，单位ms,如锁超时时间60秒，则是60*1000
     */
    private DistributedLock(String lockKey, UUID uuid, long expiryTimeMillis) {
        this.lockKey=lockKey;
        this.uuid = uuid;
        this.expiryTime = System.currentTimeMillis()+expiryTimeMillis;//###加上当前系统时间，转成时间戳
        this.lockSuccess=false;
    }
    /**
     * 根据字符串生成锁对象
     * @param text
     * @return
     */
    public static DistributedLock fromString(String text) {
        /*try {
            String[] parts = text.split(":");
            String theLockKey=parts[0];
            UUID theUUID = UUID.fromString(parts[1]);
            long theTime = Long.parseLong(parts[2]);
            return new DistributedLock(theLockKey,theUUID, theTime);
        } catch (Exception e) {
            e.printStackTrace();
            return NO_LOCK;
        }*/
         String[] parts = text.split(":");
         String theLockKey=parts[0];
         UUID theUUID = UUID.fromString(parts[1]);
         long theTime = Long.parseLong(parts[2]);
         DistributedLock instance=new DistributedLock();
         instance.lockKey=theLockKey;
         instance.uuid=theUUID;
         instance.expiryTime=theTime;
         return instance;
    }
    
    public UUID getUUID() {
        return uuid;
    }

    public long getExpiryTime() {
        return expiryTime;
    }
    
    public String getLockKey() {
        return lockKey;
        }
        public void setLockKey(String lockKey) {
                this.lockKey = lockKey;
        }
        /**
     * 重写toString
     */
    @Override
    public String toString() {
        return lockKey+":"+uuid.toString()+":"+expiryTime;  
    }
    /**
     * 判断锁是否超时
     * @return
     */
    boolean isExpired(){
        //logger.info("判断锁是否超时，lock:"+this.toString()+",getExpiryTime:"+getExpiryTime()+",now:"+System.currentTimeMillis());
        return getExpiryTime() < System.currentTimeMillis();
    }
    /**
     * 
     * @param otherUUID
     * @return
     */
    boolean isExpiredAndMine(UUID otherUUID) {
        //System.out.println("##isExpired:"+this.isExpired());
        //System.out.println("##this.getUUID().equals(otherUUID):"+this.getUUID().equals(otherUUID));
        return this.isExpired() && this.getUUID().equals(otherUUID);
    }
    /**
     * 设置当前锁对象加锁成功<br>
     * protected方法对调用做限制
     */
    protected void setLoginSuccess() {
           this.lockSuccess=true;
    }
    /**
     * 获取锁是否成功
     * @return
     */
    public boolean getLockSuccess(){
        return this.lockSuccess;
    }
    public static void main(String[] args) {
        DistributedLock lock =  DistributedLock.fromString("lock_prize_id_1@2:9e88421d-f5cc-4777-bc2d-3f7feb514bee:1512389761366");
        System.out.println(lock.getExpiryTime());
        }
}

